#include "sr.h"
#include "esp_mn_speech_commands.h"

#define TAG     "SR"

static esp_afe_sr_iface_t *afe_handle = NULL;
static esp_afe_sr_data_t *afe_data = NULL;

static esp_mn_iface_t   *multinet_handle = NULL;
static model_iface_data_t *model_data = NULL;
#define WAKE_EV_BIT     BIT0
#define VAD_EV_BIT      BIT1

static EventGroupHandle_t   afe_event_group = NULL;
static esp_sr_wakeup_cb     afe_wakeup_callback = NULL;
static esp_sr_mulit_cb      afe_mulit_callback = NULL;

/** 唤醒词检测任务
 * @param arg 任务参数
 * @return 无
 */
void wake_detect_task(void *arg)
{
    int afe_chunksize = afe_handle->get_fetch_chunksize(afe_data);
    int wakeup_flag = 0;
    ESP_LOGI(TAG, "Wake detection task started, afe_chunksize: %d",afe_chunksize);
    while (1) {
        xEventGroupWaitBits(afe_event_group,WAKE_EV_BIT,pdFALSE,pdFALSE,portMAX_DELAY);
        afe_fetch_result_t* res = afe_handle->fetch(afe_data); 
        if (!res || res->ret_value == ESP_FAIL) {
            printf("wake detect fetch error!\n");
            continue;
        }
        if (res->wakeup_state == WAKENET_DETECTED) {
            wakeup_flag = 1;
            if(afe_wakeup_callback)
                afe_wakeup_callback(true);
        }
        if (wakeup_flag == 1) {
            esp_mn_state_t mn_state = multinet_handle->detect(model_data, res->data);

            if (mn_state == ESP_MN_STATE_DETECTING) {
                continue;
            }

            if (mn_state == ESP_MN_STATE_DETECTED) {
                esp_mn_results_t *mn_result = multinet_handle->get_results(model_data);
                for (int i = 0; i < mn_result->num; i++) {
                    printf("TOP %d, command_id: %d, phrase_id: %d, string:%s prob: %f\n", 
                    i+1, mn_result->command_id[i], mn_result->phrase_id[i], mn_result->string, mn_result->prob[i]);
                    if(afe_mulit_callback)
                        afe_mulit_callback(mn_result->command_id[i]);
                }
                printf("\n-----------listening-----------\n");
            }

            if (mn_state == ESP_MN_STATE_TIMEOUT) {
                esp_mn_results_t *mn_result = multinet_handle->get_results(model_data);
                printf("timeout, string:%s\n", mn_result->string);
                afe_handle->enable_wakenet(afe_data);
                wakeup_flag = 0;
                if(afe_wakeup_callback)
                    afe_wakeup_callback(false);
                printf("\n-----------awaits to be waken up-----------\n");
                continue;
            }
        }
    }
}


/** 语音识别唤醒功能初始化
 * @param cfg 回调函数
 * @return 成功 or 失败
 */
esp_err_t esp_sr_init(ESP_SR_cb_t* cfg)
{
    srmodel_list_t *models = esp_srmodel_init("model");
    afe_config_t *afe_config = afe_config_init("M", models, AFE_TYPE_SR, AFE_MODE_LOW_COST);
    afe_config->memory_alloc_mode = AFE_MEMORY_ALLOC_MORE_PSRAM;
    afe_handle = esp_afe_handle_from_config(afe_config);
    afe_data = afe_handle->create_from_config(afe_config);

    char *mn_name = esp_srmodel_filter(models, ESP_MN_PREFIX, ESP_MN_CHINESE);
    ESP_LOGI(TAG,"multinet:%s\n", mn_name);
    multinet_handle = esp_mn_handle_from_name(mn_name);
    model_data = multinet_handle->create(mn_name, 12000);

    afe_config_free(afe_config);
    afe_wakeup_callback = cfg->wakeup_func;
    afe_mulit_callback = cfg->mulit_func;
    if(!afe_event_group)
        afe_event_group = xEventGroupCreate();
    esp_mn_commands_clear();
    return ESP_OK;
}

esp_err_t esp_sr_start(void)
{
    //唤醒检测任务
    esp_mn_commands_update();                      // 更新命令词列表
    multinet_handle->print_active_speech_commands(model_data);     // 打印当前正在使用的所有命令词条
    BaseType_t pd = xTaskCreatePinnedToCore(&wake_detect_task, "wake detect", 4 * 1024, NULL, 5, NULL, 1);
    if(pd == pdTRUE)
        return ESP_OK;
    return ESP_FAIL;
}

/** 启用/禁用唤醒词检测
 * @param enable 使能 or 失能
 * @return 无
 */
void esp_sr_enable(bool enable)
{
    if(enable)
        xEventGroupSetBits(afe_event_group,WAKE_EV_BIT);
    else
        xEventGroupClearBits(afe_event_group,WAKE_EV_BIT);
}


/** 唤醒词检测是否在进行
 * @param 无
 * @return 是 or 否
 */
bool esp_sr_is_process(void)
{
    return xEventGroupGetBits(afe_event_group) & WAKE_EV_BIT;
}

/** 获取输入数据的大小
 * @param 无
 * @return size（字）
 */
int esp_sr_get_feedsize(void)
{
    return afe_handle->get_feed_chunksize(afe_data);
}

/** 唤醒语音数据输入
 * @param data 16位pcm数据
 * @param len 数据长度,单位(字节)
 * @return 无
 */
void esp_sr_feed(int16_t *data,int len)
{
    afe_handle->feed(afe_data, data);
}

void esp_sr_add_command(int index,const char* command)
{
    esp_mn_commands_add(index, command);
}